package com.cnap.service.impl;

import com.cnap.CnapApplicationTests;
import com.cnap.db.entity.ClusterInfoPO;
import com.cnap.db.entity.MicroServicePO;
import com.cnap.db.entity.StrategyPO;
import com.cnap.db.mapper.MicroServiceMapper;
import com.cnap.db.mapper.StrategyMapper;
import com.cnap.model.cloud.CommentResultForCloud;
import com.cnap.model.cloud.DeleteLocalImageParam;
import com.cnap.model.cloud.DeleteParam;
import com.cnap.model.exception.JsonException;
import com.cnap.model.schedule.OperateParam;
import com.cnap.model.schedule.OperateTypeEnum;
import com.cnap.model.schedule.StrategyTypeEnum;
import com.cnap.model.schedule.engine.EngineClusterInfo;
import com.cnap.model.schedule.engine.OperateReq;
import com.cnap.model.schedule.engine.alg.AlgDeployClusterInfo;
import com.cnap.model.schedule.engine.alg.ResourceTypeEnum;
import com.cnap.model.stage.SingleStageVO;
import com.cnap.model.stage.StageDeployParam;
import com.cnap.model.stage.StageVO;
import com.cnap.service.AlgorithmEngineService;
import com.cnap.service.CloudMgmtService;
import com.cnap.service.ClusterInfoService;
import com.cnap.service.DistributeDeployService;
import com.cnap.service.MicroSvcService;
import com.cnap.service.OperateService;
import com.cnap.service.ScheduleService;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <类文件描述>
 *
 * @author xc
 **/
public class OperateServiceImplTest extends CnapApplicationTests {

    @Autowired
    private OperateService operateService;
    @MockBean
    private MicroServiceMapper microServiceMapperMock;

    @MockBean
    private StrategyMapper strategyMapperMock;
    @MockBean
    private AlgorithmEngineService algorithmEngineServiceMock;

    @MockBean
    private ClusterInfoService clusterInfoServiceMock;

    @MockBean
    private DistributeDeployService distributeDeployServiceMock;
    @MockBean
    private CloudMgmtService cloudMgmtServiceMock;
    @MockBean
    private ScheduleService scheduleServiceMock;
    @MockBean
    private MicroSvcService microSvcServiceMock;


    @Test
    void operateWithNoMicroservice() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.SUSPEND.getType());

        Assertions.assertThrows(JsonException.class, () -> {
            operateService.operate(param);
        });
    }

    @Test
    void operateWithNoPermissions() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.SUSPEND.getType());

        MicroServicePO microServicePO = new MicroServicePO();
        microServicePO.setUserName("12");
        Mockito.when(microServiceMapperMock.selectMicroServiceById("svcId")).thenReturn(microServicePO);

        Assertions.assertThrows(JsonException.class, () -> {
            operateService.operate(param);
        });
    }

    @Test
    void operate() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.SUSPEND.getType());

        MicroServicePO microServicePO = new MicroServicePO();
        microServicePO.setUserName("admin");
        Mockito.when(microServiceMapperMock.selectMicroServiceById("svcId")).thenReturn(microServicePO);

        Mockito.when(algorithmEngineServiceMock.operate(Mockito.any(OperateReq.class))).thenReturn(null);

        StrategyPO scheduleStrategy = new StrategyPO();
        Mockito.when(strategyMapperMock.selectStrategyByServiceIdAndType("svcId", StrategyTypeEnum.SCHEDULE_STRATEGY.getValue()))
                .thenReturn(scheduleStrategy);
        ClusterInfoPO clusterInfoPO = new ClusterInfoPO();
        Mockito.when(clusterInfoServiceMock.getClusterInfoBySvcId("svcId")).thenReturn(clusterInfoPO);
        Mockito.doNothing().when(scheduleServiceMock).addScheduleStrategy(Mockito.any());


        StageVO stageVO = new StageVO();
        stageVO.setFourthStages(Collections.singletonList(new SingleStageVO()));
        Mockito.when(distributeDeployServiceMock.getStageInfoByServiceId("svcId")).thenReturn(stageVO);

        Assertions.assertDoesNotThrow(() -> {
            operateService.operate(param);
        });
    }

    @Test
    void operateWithDelete() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.DELETE.getType());

        MicroServicePO microServicePO = new MicroServicePO();
        microServicePO.setUserName("admin");
        microServicePO.setImageName("imageName");
        Mockito.when(microServiceMapperMock.selectMicroServiceById("svcId")).thenReturn(microServicePO);

        Mockito.when(algorithmEngineServiceMock.operate(Mockito.any(OperateReq.class))).thenReturn(null);

        StageVO stageVO = new StageVO();
        stageVO.setFourthStages(Collections.singletonList(new SingleStageVO()));
        SingleStageVO singleStageVO = new SingleStageVO();
        singleStageVO.setSuccess(false);
        stageVO.setFirstStages(Collections.singletonList(singleStageVO));
        stageVO.setSecondStages(Collections.emptyList());
        stageVO.setThirdStages(Collections.emptyList());
        Mockito.when(distributeDeployServiceMock.getStageInfoByServiceId("svcId")).thenReturn(stageVO);


        Mockito.when(strategyMapperMock.deleteStrategyBySvcId("svcId")).thenReturn(1);
        Mockito.when(distributeDeployServiceMock.deleteStagesByServiceId("svcId")).thenReturn(true);
        Mockito.doNothing().when(clusterInfoServiceMock).deleteClusterInfoBySvcId("svcId");
        Mockito.when(microServiceMapperMock.updateMicroServiceStatus("svcId",
                OperateTypeEnum.DELETE.getStatusValue())).thenReturn(1);

        ClusterInfoPO clusterInfoPO = new ClusterInfoPO();
        clusterInfoPO.setUserChooseCloud("Huawei");
        EngineClusterInfo engineClusterInfo = new EngineClusterInfo();
        engineClusterInfo.setProviderName("Huawei");
        clusterInfoPO.setClusterInfos(Collections.singletonList(engineClusterInfo));
        Mockito.when(clusterInfoServiceMock.getClusterInfoBySvcId("svcId")).thenReturn(clusterInfoPO);

        CommentResultForCloud cloud = new CommentResultForCloud();
        cloud.setCode(500);
        Mockito.when(cloudMgmtServiceMock.deleteLocalImageByServiceInfo(Mockito.any(DeleteLocalImageParam.class))).thenReturn(cloud);
        Mockito.when(cloudMgmtServiceMock.deleteVmAndOtherInfo(Mockito.any(DeleteParam.class))).thenReturn(cloud);

        Assertions.assertDoesNotThrow(() -> {
            operateService.operate(param);
        });
    }

    @Test
    void operateWithDeleteToMulti() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.DELETE.getType());

        MicroServicePO microServicePO = new MicroServicePO();
        microServicePO.setUserName("admin");
        microServicePO.setImageName("imageName");
        Mockito.when(microServiceMapperMock.selectMicroServiceById("svcId")).thenReturn(microServicePO);

        Mockito.when(algorithmEngineServiceMock.operate(Mockito.any(OperateReq.class))).thenReturn(null);

        StageVO stageVO = new StageVO();
        stageVO.setFourthStages(Collections.emptyList());
        SingleStageVO singleStageVO = new SingleStageVO();
        singleStageVO.setSuccess(true);
        stageVO.setFirstStages(Collections.singletonList(singleStageVO));
        stageVO.setSecondStages(Collections.emptyList());
        stageVO.setThirdStages(Collections.emptyList());
        Mockito.when(distributeDeployServiceMock.getStageInfoByServiceId("svcId")).thenReturn(stageVO);


        Mockito.when(strategyMapperMock.deleteStrategyBySvcId("svcId")).thenReturn(1);
        Mockito.when(distributeDeployServiceMock.deleteStagesByServiceId("svcId")).thenReturn(true);
        Mockito.doNothing().when(clusterInfoServiceMock).deleteClusterInfoBySvcId("svcId");
        Mockito.when(microServiceMapperMock.updateMicroServiceStatus("svcId",
                OperateTypeEnum.DELETE.getStatusValue())).thenReturn(1);

        ClusterInfoPO clusterInfoPO = new ClusterInfoPO();
        clusterInfoPO.setUserChooseCloud("Huawei");
        EngineClusterInfo engineClusterInfo = new EngineClusterInfo();
        engineClusterInfo.setProviderName("Huawei");
        clusterInfoPO.setClusterInfos(Collections.singletonList(engineClusterInfo));
        Mockito.when(clusterInfoServiceMock.getClusterInfoBySvcId("svcId")).thenReturn(clusterInfoPO);

        CommentResultForCloud cloud = new CommentResultForCloud();
        cloud.setCode(500);
        Mockito.when(cloudMgmtServiceMock.deleteLocalImageByServiceInfo(Mockito.any(DeleteLocalImageParam.class))).thenReturn(cloud);
        Mockito.when(cloudMgmtServiceMock.deleteVmAndOtherInfo(Mockito.any(DeleteParam.class))).thenReturn(cloud);

        Assertions.assertDoesNotThrow(() -> {
            operateService.operate(param);
        });
    }


    @Test
    void operateWithResumeWithReDistribute() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.RESUME.getType());

        MicroServicePO microServicePO = new MicroServicePO();
        microServicePO.setUserName("admin");
        Mockito.when(microServiceMapperMock.selectMicroServiceById("svcId")).thenReturn(microServicePO);

        Mockito.when(algorithmEngineServiceMock.operate(Mockito.any(OperateReq.class))).thenReturn(null);
        StrategyPO strategyPO = new StrategyPO();

        EngineClusterInfo engineClusterInfo = new EngineClusterInfo();
        engineClusterInfo.setName("name");
        engineClusterInfo.setProviderName("Huawei");
        List<EngineClusterInfo> list = new ArrayList<>();
        list.add(engineClusterInfo);
        strategyPO.setClusterInfos(list);

        EngineClusterInfo oldEngine = new EngineClusterInfo();
        oldEngine.setProviderName("Huawei");
        oldEngine.setActive(true);
        strategyPO.setOldClusterInfos(Collections.singletonList(oldEngine));

        ClusterInfoPO clusterInfoPO = new ClusterInfoPO();
        AlgDeployClusterInfo algDeployClusterInfo = new AlgDeployClusterInfo();
        algDeployClusterInfo.setProviderName("Huawei");
        algDeployClusterInfo.setResourceType(ResourceTypeEnum.EXIST.getType());
        algDeployClusterInfo.setName("name");
        clusterInfoPO.setAlgDeployClusterInfos(Collections.singletonList(algDeployClusterInfo));
        clusterInfoPO.setForcedIsolation(false);
        clusterInfoPO.setUserChooseCloud("Huawei");
        clusterInfoPO.setClusterInfos(list);
        clusterInfoPO.setRecommendCloud("Huawei");
        Mockito.when(clusterInfoServiceMock.getClusterInfoBySvcId("svcId")).thenReturn(clusterInfoPO);

        StrategyPO vmStrategy = new StrategyPO();
        vmStrategy.setStrategyParam("{\"policy\":\"vm\",\"param\":[{\"id\":\"a7156a5eba084ff7b8753a9b0a38204a\",\"duration\":5,\"continuousNum\":1,\"coolTime\":88,\"type\":\"max\",\"num\":1,\"resource\":\"cpu\",\"value\":79,\"groupId\":\"63a5e2ca6e3e4d7184e440a4d01e2423\"},{\"id\":\"b7d3f6d3f2334a909692d3f4b65909b9\",\"duration\":5,\"continuousNum\":1,\"coolTime\":77,\"type\":\"min\",\"num\":1,\"resource\":\"cpu\",\"value\":77,\"groupId\":\"63a5e2ca6e3e4d7184e440a4d01e2423\"}]}");

        Mockito.when(strategyMapperMock.selectVmScaleByServiceId("svcId")).thenReturn(vmStrategy);



        Mockito.when(strategyMapperMock.selectStrategyByServiceIdAndType("svcId",
                StrategyTypeEnum.SCHEDULE_STRATEGY.getValue())).thenReturn(strategyPO);

        Mockito.doNothing().when(distributeDeployServiceMock).startDistributeDeploy(Mockito.any(StageDeployParam.class));

        Assertions.assertDoesNotThrow(() -> {
            operateService.operate(param);
        });
    }

    @Test
    void operateWithResume() {
        OperateParam param = new OperateParam();
        param.setSvcId("svcId");
        param.setOperationType(OperateTypeEnum.RESUME.getType());

        MicroServicePO microServicePO = new MicroServicePO();
        microServicePO.setUserName("admin");
        microServicePO.setCategory("AI");
        Mockito.when(microServiceMapperMock.selectMicroServiceById("svcId")).thenReturn(microServicePO);

        Mockito.when(algorithmEngineServiceMock.operate(Mockito.any(OperateReq.class))).thenReturn(null);
        StrategyPO strategyPO = new StrategyPO();

        EngineClusterInfo engineClusterInfo = new EngineClusterInfo();
        engineClusterInfo.setName("name");
        List<EngineClusterInfo> list = new ArrayList<>();
        list.add(engineClusterInfo);
        strategyPO.setClusterInfos(list);

        EngineClusterInfo oldEngine = new EngineClusterInfo();
        oldEngine.setProviderName("Huawei");
        oldEngine.setActive(true);
        strategyPO.setOldClusterInfos(Collections.singletonList(oldEngine));

        ClusterInfoPO clusterInfoPO = new ClusterInfoPO();
        AlgDeployClusterInfo algDeployClusterInfo = new AlgDeployClusterInfo();
        algDeployClusterInfo.setProviderName("Huawei");
        algDeployClusterInfo.setResourceType(ResourceTypeEnum.CREATE.getType());
        clusterInfoPO.setAlgDeployClusterInfos(Collections.singletonList(algDeployClusterInfo));
        clusterInfoPO.setForcedIsolation(false);
        clusterInfoPO.setUserChooseCloud("Huawei");
        clusterInfoPO.setClusterInfos(list);

        Mockito.when(clusterInfoServiceMock.getClusterInfoBySvcId("svcId")).thenReturn(clusterInfoPO);


        Mockito.when(strategyMapperMock.selectStrategyByServiceIdAndType("svcId",
                StrategyTypeEnum.SCHEDULE_STRATEGY.getValue())).thenReturn(strategyPO);

        StrategyPO vmStrategy = new StrategyPO();
        vmStrategy.setServiceId("svcId");

        Mockito.when(strategyMapperMock.selectVmScaleByServiceId("svcId")).thenReturn(vmStrategy);

        Mockito.doNothing().when(distributeDeployServiceMock).startDistributeDeploy(Mockito.any(StageDeployParam.class));

        Assertions.assertDoesNotThrow(() -> {
            operateService.operate(param);
        });
    }
}
